"""
A class to store information 'About' a column of data. 

The key method is 'keep' which stores information about a new datum in
a set of contexts. For example, if a row has a class 'car' then
details about the cells in that car will be stored in in 'car' as well
as in a special 'allover' context that accummulates details over all
contexts.

The real work of this code is done by Num or Sym objects.  In fact,
most of 'About' is a traffic code that keeps details on Nums or Syms
stored in different contexts.

This code is part of KNIFE: cropping complexity, culling confusion, 
and cutting the crap since 2012
   
           .----------------._________________
           |=()=========---  \-----------     `\ 
      jgs  \_________________/^^^^^^^^^^^^^^^^^^

(c) 2012, Tim Menzies, tim@menzies.us, LGPL v3.0

Todo
----
for numberic classes, this class divides the data far too much.

"""

from thing import *

class About(object) :
  def __init__(self,n,name,weight,
               details=Sym,klassp=False): 
    """
    'contexts' is a place to store all contexts.
    'cllover' is some place to store summaries from all contexts.
    'aetails' is class from which we generate object to store data.
    'index' is a back index remembering what rows have some data 
    (this index will be used to optimize rule-based programming, one day).
    """
    self.allover="__"
    self.weight  = weight
    self.details = details
    self.klassp  = klassp
    self.name    = name
    self.pos     = n
    self.contexts = Dict()
    self.contexts[self.allover] = details()
    self.index=Dict()

  def clone(self) :
    "Returns the same kind on 'About' object with counts zero-ed out."
    return About(self.pos,self.name,self.weight,
                 self.details,self.klassp)

  def isNumeric(self) :
    "Returns true if this column is about numerics."
    return self.details == Num

  def all(self):
    "Returns the data held in the 'allover' context."
    return self.contexts[self.allover]

  def keep(self,at,x,row) :
    """
    Ignore unknown values, remember what row had this datum,
    then store information about 'x' in the 'allover' context
    as well at the context named 'at'.
    """
    if x== '?': return x
    self.index.push(x,row)
    out = self.store(self.allover,x,row) 
    out = self.store(at,x,row)
    return out

  def store(self,at,x,row) :
    """
    Keep something in a context. If we have no keeper yet,
    then create one from 'details'.
    """
    context = self.contexts.at(at,(lambda : self.details()))
    return context.keep(x)
